using System;
using System.Collections.Generic;
using System.Text;
using System.Reflection;
using System.IO;
using System.Collections;
using Microsoft.SqlServer.Dts.Runtime;
using System.Runtime.Remoting;


namespace Microsoft.SharedSource.SqlServer.MDDE.Components
{
    public sealed class MDDEComponentFactory
    {
        private static Hashtable componentTypeMapping = new Hashtable();

        public static void InitializeFactory()
        {
            MDDEComponentFactory.componentTypeMapping.Clear();
            Assembly assembly = Assembly.GetAssembly(typeof(MDDEComponentFactory));
            MDDEComponentFactory.LoadComponentInfo(assembly);

            if (Directory.Exists(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location) +
                "\\Component"))
            {
                string[] files =
                    Directory.GetFiles(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location) +
                    "\\Component", "*.dll");

                if (files.Length > 0)
                {
                    foreach (string fileName in files)
                    {
                        assembly = Assembly.LoadFile(fileName);
                        MDDEComponentFactory.LoadComponentInfo(assembly);
                    }
                }
            }
        }

        public static MDDEComponent CreateInstance(
            Package package, string componentClassName, object component, string name, string uri)
        {
            Type componentType = 
                (Type)MDDEComponentFactory.componentTypeMapping[componentClassName];

            if (null == componentType)
            {
                MDDEComponentFactory.InitializeFactory();
                componentType = (Type)MDDEComponentFactory.componentTypeMapping[componentClassName];
                if (null == componentType)
                {
                    throw new NotSupportedException(
                        "Type " + componentClassName+" is not supported.");
                }
            }

            Object[] parameters = new Object[4];

            parameters[0] = package;
            parameters[1] = component;
            parameters[2] = name;
            parameters[3] = uri;

            return (MDDEComponent)Activator.CreateInstance(componentType, parameters);
            
            //switch (componentClassName)
            //{
            //    case "Microsoft.SqlServer.Dts.Tasks.ExecuteSQLTask.ExecuteSQLTask, Microsoft.SqlServer.SQLTask, Version=9.0.242.0, Culture=neutral, PublicKeyToken=89845dcd8080cc91":
            //        return new MDDETask(component, name, uri);
            //    case "STOCK:SEQUENCE":
            //    case "STOCK:FOREACHLOOP":
            //        return new MDDEContainer(component, name, uri);
            //    case "DTS.Pipeline.1":
            //        return new MDDEDataFlowTask(component, name, uri);
            //    case "{90C7770B-DE7C-435E-880E-E718C92C0573}":
            //    case "{2C0A8BE5-1EDC-4353-A0EF-B778599C65A0}":
            //        return new MDDEDataFlowSource(component, name, uri);
            //    case "{A1DF9F6D-8EE4-4EF0-BB2E-D526130D7A7B}":
            //    case "{E2568105-9550-4F71-A638-B7FE42E66922}":
            //    case "{C60ACAD1-9BE8-46B3-87DA-70E59EADEA46}":
            //        return new MDDEDataFlowDestination(component, name, uri);
            //    case "{0FB4AABB-C027-4440-809A-1198049BF117}":
            //    case "{9CF90BF0-5BCC-4C63-B91D-1F322DC12C26}":
            //    case "{DE50D3C7-41AF-4804-9247-CF1DEB147971}":
            //    case "{08AE886A-4124-499C-B332-16E3299D225A}":
            //        return new MDDEDataFlowTransformation(component, name, uri);
            //    case "Microsoft.SqlServer.Dts.Runtime.ConnectionManager":
            //        return new MDDEConnectionManager(component, name, uri);
            //    case "Microsoft.SqlServer.Dts.Runtime.Variable":
            //        return new MDDEVariable(component, name, uri);
            //    default:
            //        throw new NotSupportedException();
            //}
        }

        private static void LoadComponentInfo(Assembly assembly)
        {
            Type[] types = assembly.GetTypes();

            foreach(Type type in types)
            {
                if (type.IsSubclassOf(typeof(MDDEComponent)))
                {
                    Object[] customAttributes = type.GetCustomAttributes(false);

                    foreach (Object customAttribute in customAttributes)
                    {
                        if (customAttribute is SupportedComponentType)
                        {
                            string componentType = 
                                (customAttribute as SupportedComponentType).componentType;
                            //If two classes claims to support one component, we will use subclass, 
                            //if classes has baseclass subclass relationship, throw exception 
                            //otherwise.
                            if (MDDEComponentFactory.componentTypeMapping.Contains(componentType))
                            {
                                Type storedType =
                                    (Type)MDDEComponentFactory.componentTypeMapping[componentType];
                                if (type.IsSubclassOf(storedType))
                                    MDDEComponentFactory.componentTypeMapping[componentType] = type;
                                else if (storedType != type && !storedType.IsSubclassOf(type))
                                    throw new Exception();
                            }
                            else
                            {
                                MDDEComponentFactory.componentTypeMapping.Add(
                                    (customAttribute as SupportedComponentType).componentType, type);
                            }
                        }
                    }
                }
            }
        }

    }
}
